package com.someclip.component.core
{
	import com.someclip.component.controlls.SimpleButtonExtend;
	import com.someclip.component.interfaces.IComponent;
	import com.someclip.component.interfaces.ISomeSprite;

	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.Shape;
	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.Dictionary;
	import flash.utils.getDefinitionByName;

	/**
	 * ...
	 * @author Argus
	 */
	public class Component extends SomeSprite implements IComponent, ISomeSprite, IEventDispatcher
	{
		private var _id:String;
		private var _styleLink:Object;
		private var _styleInstance:Object;
		protected var childList:Array=[];
		private var _completed:Boolean=false;
		private var _w:Number;
		private var _h:Number;
		private var _ow:Number;
		private var _oh:Number;
		private const defaultW:Number=100;
		private const defaultH:Number=100;
		private var _stickWithParent:Boolean=false;
		private var _fillColor:int=-1;
		//布局属性
		private var _top:String;
		private var _bottom:String;
		private var _vCenter:String;

		private var _left:String;
		private var _right:String;
		private var _hCenter:String;
		private var _parentW:Number;
		private var _parentH:Number;
		private var _bound:Rectangle;
		private var _thisResized:Boolean=false;

		private var _layoutEnable:Boolean=true;

		private var _masker:Sprite;
		private var _useMask:Boolean=true;

		public final function get top():Number
		{
			if (_top == null || _top == "" || _top == "NaN")
				return NaN;
			return Number(_top);
		}

		public final function set top(value:Number):void
		{
			_top=String(value);
			_bottom="";
			_vCenter="";
			updateLayout();
		}

		public final function get bottom():Number
		{
			if (_bottom == null || _bottom == "" || _bottom == "NaN")
				return NaN;
			return Number(_bottom);
		}

		public final function set bottom(value:Number):void
		{
			_bottom=String(value);
			_top="";
			_vCenter="";
			updateLayout();
		}

		public final function get vCenter():Number
		{
			if (_vCenter == null || _vCenter == "" || _vCenter == "NaN")
				return NaN;
			return Number(_vCenter);
		}

		public final function set vCenter(value:Number):void
		{
			_vCenter=String(value);
			_top="";
			_bottom="";
			updateLayout();
		}

		public final function get left():Number
		{
			if (_left == null || _left == "" || _left == "NaN")
				return NaN;
			return Number(_left);
		}

		public final function set left(value:Number):void
		{
			_left=String(value);
			_right="";
			_hCenter="";
			updateLayout();
		}

		public final function get right():Number
		{
			if (_right == null || _right == "" || _right == "NaN")
				return NaN;
			return Number(_right);
		}

		public final function set right(value:Number):void
		{
			_right=String(value);
			_left="";
			_hCenter="";
			updateLayout();
		}

		public final function get hCenter():Number
		{
			if (_hCenter == null || _hCenter == "" || _hCenter == "NaN")
				return NaN;
			return Number(_hCenter);
		}

		public final function set hCenter(value:Number):void
		{
			_hCenter=String(value);
			_left="";
			_right="";
			updateLayout();
		}

		public function get styleLink():Object
		{
			if (!(_styleLink is String))
				return "";
			return _styleLink;
		}

		public function set styleLink(value:Object):void
		{
			_styleLink=value;
			updateStyle();
		}

		public function get id():String
		{
			return _id;
		}

		public function set id(value:String):void
		{
			_id=value;
		}

		override public function set x(value:Number):void
		{
			if (_completed && _layoutEnable)
			{
				var tempX:Number=caculateX(value);
				super.x=tempX;
			}
			else
			{
				super.x=value;
			}
			updateMasker();
		}

		override public function set y(value:Number):void
		{
			if (_completed && _layoutEnable)
			{
				var tempY:Number=caculateY(value);
				super.y=tempY;
			}
			else
			{
				super.y=value;
			}
			updateMasker();
		}

		override public function get width():Number
		{
			if (isNaN(_w))
			{
				_w=defaultW;
				_ow=_w;
				_thisResized=true;
			}
			return _w;
		}

		override public function set width(value:Number):void
		{
			_w=value;
			if (!isNaN(_oh))
			{
				if (_w != _ow)
				{
					_ow=_w;
					_thisResized=true;
				}
			}
			else
			{
				_ow=_w;
				_thisResized=true;
			}
			if (_thisResized)
				updateLayout();
		}

		override public function get height():Number
		{
			if (isNaN(_h))
			{
				_h=defaultH;
				_oh=_h;
				_thisResized=true;
			}
			return _h;
		}

		override public function set height(value:Number):void
		{
			_h=value;
			if (!isNaN(_oh))
			{
				if (_h != _oh)
				{
					_oh=_w;
					_thisResized=true;
				}
			}
			else
			{
				_oh=_w;
				_thisResized=true;
			}
			if (_thisResized)
				updateLayout();
		}

		private function updateMasker():void
		{
			if (!_useMask)
				return;
			if (!_masker)
			{
				_masker=new Sprite();

			}
			_masker.graphics.clear();
			_masker.graphics.beginFill(0xff0000, 1);
			_masker.graphics.drawRect(0, 0, this.width, this.height);
			_masker.graphics.endFill();
			updateMaskerPosition();
			//	this.mask=_masker;
		}


		private function updateMaskerPosition():void
		{
			if (_masker)
			{
				if (this.parent)
				{
					var point:Point=this.parent.localToGlobal(new Point(this.x, this.y));
					_masker.x=point.x;
					_masker.y=point.y;
				}
			}
		}

		private function caculateX(value:Number):Number
		{

			if (!isNaN(right))
			{
				return _parentW - this.width - right;
			}
			if (!isNaN(left))
			{
				return left;
			}
			if (!isNaN(hCenter))
			{
				return _parentW / 2 - this.width / 2 + hCenter;
			}
			return value;
		}

		private function caculateY(value:Number):Number
		{
			if (!isNaN(bottom))
			{
				return _parentH - this.height - bottom
			}
			if (!isNaN(top))
			{
				return top;
			}
			if (!isNaN(vCenter))
			{
				return _parentH / 2 - this.height / 2 + vCenter;
			}
			return value;
		}

		public function get fillColor():int
		{
			return _fillColor;
		}

		public function set fillColor(value:int):void
		{
			_fillColor=value;
			fillBg();
		}

		public function get stickWithParent():Boolean
		{
			return _stickWithParent;
		}

		public function set stickWithParent(value:Boolean):void
		{
			_stickWithParent=value;
		}

		public function get layoutEnable():Boolean
		{
			return _layoutEnable;
		}

		public function set layoutEnable(value:Boolean):void
		{
			_layoutEnable=value;
		}

		protected function get useMask():Boolean
		{
			return _useMask;
		}

		protected function set useMask(value:Boolean):void
		{
			_useMask=value;
		}

		public function Component()
		{
			this.addEventListener(Event.ADDED_TO_STAGE, handleThisAddedToStage);
		}

		private function handleThisAddedToStage(e:Event):void
		{
			_completed=true;
			removeEventListener(Event.ADDED_TO_STAGE, handleThisAddedToStage);
			this.addEventListener(Event.REMOVED_FROM_STAGE, handleThisRemovedFromStage);
			if (_stickWithParent)
			{
				if (this.parent is Stage)
				{
					this.width=Stage(this.parent).stageWidth;
					this.height=Stage(this.parent).stageHeight;
				}
				else
				{
					this.width=this.parent.width;
					this.height=this.parent.height;
				}
			}

			if (!_styleInstance)
				updateStyle();
			updateLayout();
			if (this.parent is Stage || !(this.parent is Component))
			{
				stage.addEventListener(Event.RESIZE, handleThisResize);
			}
		}

		private function handleThisResize(e:Event):void
		{
			if (!_completed)
			{
				return;
			}
			if (stickWithParent)
			{
				if (this.parent is Stage)
				{
					this.width=Stage(this.parent).stageWidth;
					this.height=Stage(this.parent).stageHeight;
				}
				else
				{
					this.width=this.parent.width;
					this.height=this.parent.height;
				}
			}
			updateLayout();
		}

		private function handleThisRemovedFromStage(e:Event):void
		{
			if (stage.hasEventListener(Event.RESIZE))
				stage.removeEventListener(Event.RESIZE, handleThisResize);
			removeEventListener(Event.REMOVED_FROM_STAGE, handleThisRemovedFromStage);
			this.addEventListener(Event.ADDED_TO_STAGE, handleThisAddedToStage);
		}

		public function updateLayout():void
		{
			if (!_completed)
			{
				return;
			}
			updateThisSize();
			updateMaskerPosition();
			if (!_layoutEnable)
			{
				return;
			}
			fillBg();
			if (_styleInstance)
			{
				(_styleInstance as DisplayObject).width=this.width;
				(_styleInstance as DisplayObject).height=this.height;
			}
			if (this.parent is Stage)
			{
				_parentW=(this.parent as Stage).stageWidth;
				_parentH=(this.parent as Stage).stageHeight;
			}
			else
			{
				_parentW=this.parent.width;
				_parentH=this.parent.height;
			}

			_bound=this.getBounds(this);

			this.x=super.x;
			this.y=super.y;
			updateMasker();
			if (_fillColor != -1)
				this.fillColor=_fillColor;
			/*if (_thisResized)
			{*/

			for each (var child:Object in childList)
			{
				if (child.children is Component)
				{
					Component(child.children).updateLayout();
				}
			}
			_thisResized=false;
		/*}*/
		}

		private function updateThisSize():void
		{
			if (!_completed)
				return;
			if (stickWithParent)
			{
				if (this.parent is Stage)
				{
					_w=Stage(this.parent).stageWidth;
					_h=Stage(this.parent).stageHeight;
				}
				else
				{
					_w=this.parent.width;
					_h=this.parent.height;
				}
			}
		}

		private function updateStyle():void
		{
			if (_styleLink == null)
			{
				return;
			}
			if (_styleInstance)
			{
				if (contains(_styleInstance as DisplayObject))
				{
					super.removeChild(_styleInstance as DisplayObject);
				}
				if (_styleInstance is MovieClip)
				{
					MovieClip(_styleInstance).stop();
				}
				if (_styleInstance is Bitmap)
				{
					Bitmap(_styleInstance).bitmapData.dispose();
				}
				_styleInstance=null;
			}
			if (_styleLink is DisplayObject)
			{
				if (_styleLink is BitmapData)
				{
					_styleInstance=new Bitmap(_styleLink as BitmapData);
				}
				_styleInstance=_styleLink;
			}
			else if (_styleLink is String && _styleLink != "")
			{
				var tmpClass:Class;
				try
				{
					tmpClass=getDefinitionByName(String(_styleLink)) as Class;
				}
				catch (e:*)
				{
					trace("找不到样式:", _styleLink);
				}
				if (tmpClass)
				{

					_styleInstance=new tmpClass();
					if (_styleInstance is MovieClip)
					{
						MovieClip(_styleInstance).gotoAndStop(1);
					}
					if (_styleInstance is BitmapData)
					{
						_styleInstance=new Bitmap(_styleInstance as BitmapData);
					}
					if (_styleInstance is SimpleButton)
					{
						_styleInstance=new SimpleButtonExtend((_styleInstance as SimpleButton).upState, (_styleInstance as SimpleButton).overState, (_styleInstance as SimpleButton).downState, (_styleInstance as SimpleButton).hitTestState);
					}
				}
			}
			if (_styleInstance)
			{
				super.addChildAt(_styleInstance as DisplayObject, 0);
				_fillColor=-1;
				fillBg();
				(_styleInstance as DisplayObject).width=this.width;
				(_styleInstance as DisplayObject).height=this.height;
			}
		}

		private function fillBg():void
		{
			this.graphics.clear();
			if (_fillColor == -1)
			{
				this.graphics.beginFill(0xffffff, 0);
			}
			else
			{
				this.graphics.beginFill(_fillColor, 1);
			}
			this.graphics.drawRect(0, 0, this.width, this.height);
			this.graphics.endFill();

		}

		override public function addChild(child:DisplayObject):DisplayObject
		{
			super.addChild(child);
			pushChildList(child);
			return child;
		}

		override public function addChildAt(child:DisplayObject, index:int):DisplayObject
		{
			if (index == 0 && _styleInstance)
			{
				super.addChildAt(child, index + 1);
			}
			else
			{
				super.addChildAt(child, index);
			}
			pushChildList(child, index);
			return child;
		}

		override public function removeChild(child:DisplayObject):DisplayObject
		{
			super.removeChild(child)
			spliceChildList(child);
			return child;
		}

		override public function removeChildAt(index:int):DisplayObject
		{
			var child:DisplayObject=super.removeChildAt(index);
			spliceChildList(child);
			return child;
		}

		private function pushChildList(child:DisplayObject, index:int=-1):void
		{
			if (_styleInstance != null && child == _styleInstance)
				return;
			var len:uint=childList.length;
			if (len == 0)
			{
				childList.push({children: child, bound: child.getBounds(child)});
				return;
			}
			for (var i:uint=0; i < len; i++)
			{
				if (childList[i].children == child)
				{
					return;
				}
			}
			if (index != -1)
			{
				childList.splic(index, 0, {children: child, bound: child.getBounds(child)});
			}
			else
			{
				childList.push({children: child, bound: child.getBounds(child)});
			}
		}

		private function spliceChildList(child:DisplayObject):void
		{
			if (_styleInstance != null && child == _styleInstance)
				return;
			var len:uint=childList.length;
			if (len == 0)
			{
				return;
			}
			for (var i:uint=0; i < len; i++)
			{
				if (childList[i].children == child)
				{
					childList.splice(i, 1);
					return;
				}
			}
		}

		override public function startDrag(lockCenter:Boolean=false, bounds:Rectangle=null):void
		{
			super.startDrag(lockCenter, bounds);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, handleStageMouseOver);
		}

		private function handleStageMouseOver(e:MouseEvent):void
		{
			updateMasker();
		}

		override public function stopDrag():void
		{
			super.stopDrag();
			stage.addEventListener(MouseEvent.MOUSE_MOVE, handleStageMouseOver);
		}

		override public function getChildAt(index:int):DisplayObject
		{
			return childList[index].children;
//			if (_styleInstance)
//				return super.getChildAt(index + 1);
//			return super.getChildAt(index);
		}

		override public function get numChildren():int
		{
			if (_styleInstance)
				return super.numChildren - 1;
			return super.numChildren;
		}

		public function getChildById(id:String):IComponent
		{
			for each (var child:DisplayObject in childList)
			{
				if (child is IComponent && (child as IComponent).id == id)
				{
					return child as IComponent;
				}
			}
			return null;
		}
	}

}
